package com.cci.kangdao.fieldService.service.impl;

import com.cci.kangdao.common.RedisKeys;
import com.cci.kangdao.fieldService.model.FieldServiceEngineer;
import com.cci.kangdao.fieldService.model.FieldServiceItem;
import com.cci.kangdao.fieldService.model.FieldServiceWorkOrder;
import com.cci.kangdao.fieldService.model.SyncModel;
import com.cci.kangdao.fieldService.model.type.SyncInterface;
import com.cci.kangdao.fieldService.service.SyncCCGService;
import com.cci.kangdao.fieldService.service.SyncProcessor;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.utilTool.JsonUtils;
import com.cci.kangdao.utilTool.LocalTimeUtil;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author William Du
 * @date 2020/1/11
 */
@Service
public class SyncProcessorImpl implements SyncProcessor {

    private static final Logger logger = Logger.getLogger(SyncCCGService.class);

    public static final Long fieldSyncLockTime = 10 * 60L;

    @Resource
    private RedisClientUtils redisClientUtils;

    @Resource
    private SyncCCGService syncCCGService;

    @Override
    public void syncInfoToCrm(Long itemId, SyncInterface syncInterface, Object... args) {
        try {
            // 尝试给同步列表加锁
            Boolean lock = redisClientUtils.lock(RedisKeys.fieldSyncLockKey(String.valueOf(itemId)), fieldSyncLockTime);
            // 如果加锁失败，说明其他线程在处理该同步列表，等待重试加锁
            while (!lock) {
                try {
                    Thread.sleep(100L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lock = redisClientUtils.lock(RedisKeys.fieldSyncLockKey(String.valueOf(itemId)), fieldSyncLockTime);
            }
            // 1.初始化同步对象
            SyncModel syncModel = new SyncModel();
            syncModel.setItemId(String.valueOf(itemId));
            syncModel.setSyncInterface(syncInterface);
            syncModel.setOrder(getSyncOrder(syncInterface));
            syncModel.setArgs(args);
            syncModel.setActionTime(LocalTimeUtil.getRealCurrentTime());
            // 2.将同步对象放入缓存
            List<SyncModel> syncModelList;
            String syncListStr = redisClientUtils.hget(RedisKeys.fieldSyncMapKey(), syncModel.getItemId());
            if (StringUtils.isEmpty(syncListStr)) {
                syncModelList = new ArrayList<>();
            } else {
                syncModelList = JsonUtils.convertJsonArrayToList(syncListStr, SyncModel.class);
            }
            syncModelList.add(syncModel);
            redisClientUtils.hset(RedisKeys.fieldSyncMapKey(), syncModel.getItemId(), JsonUtils.toJsonString(syncModelList));
            // 3.操作同步队列
            syncCCGService.process(syncModel.getItemId());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            // 异常情况下，此处删除锁
            redisClientUtils.delkey(RedisKeys.fieldSyncLockKey(String.valueOf(itemId)));
        }
    }

    @Override
    public void syncOrderCreateInfoToCrm(Long itemId, FieldServiceEngineer engineer, FieldServiceItem item, FieldServiceWorkOrder workOrder) {
        this.syncInfoToCrm(itemId, SyncInterface.SYNC_ITEM, engineer, item);
        this.syncInfoToCrm(itemId, SyncInterface.SYNC_WORK, workOrder);
    }

    private Integer getSyncOrder(SyncInterface syncInterface) {
        if (SyncInterface.SYNC_ITEM.equals(syncInterface)) {
            return 1;
        } else if (SyncInterface.SYNC_WORK.equals(syncInterface)) {
            return 2;
        } else {
            return 3;
        }
    }

    @Override
    public void syncRetry() {
        Map<String, Object> syncMap = redisClientUtils.getObjectMap(RedisKeys.fieldSyncMapKey());
        if (MapUtils.isNotEmpty(syncMap)) {
            for (String syncItemId : syncMap.keySet()) {
                Boolean lock = redisClientUtils.lock(RedisKeys.fieldSyncLockKey(syncItemId), fieldSyncLockTime);
                // 如果加锁失败，说明其他线程在处理该同步列表，直接进行下一个
                if (!lock) {
                    continue;
                }
                syncCCGService.process(syncItemId);
            }
        }
    }

    @Override
    public void removeRetry(Long itemId) {
        redisClientUtils.hdel(RedisKeys.fieldSyncMapKey(), String.valueOf(itemId));
    }


}
